﻿using ELTE.SEM.Data.Repository;
using ELTE.SEM.Data.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace ELTE.SEM.Data.Managers
{
    public class LogEntryManager : ManagerBase
    {
        ErrorLogRepository ErrorLogRepo { get; set; }
        SEMLogRepository Repo { get; set; }
        SEMLogEntryPartRepository EntryPartRepo { get; set; }
        SEMLogEntryTypeRepository EntryTypeRepo { get; set; }
        UsersRepository UserRepo { get; set; }
        ClientsRepository ClientRepo { get; set; }


        public LogEntryManager()
            : base()
        {
            ErrorLogRepo = new ErrorLogRepository(this.Entities);
            Repo = new SEMLogRepository(this.Entities);
            EntryPartRepo = new SEMLogEntryPartRepository(this.Entities);
            EntryTypeRepo = new SEMLogEntryTypeRepository(this.Entities);
            UserRepo = new UsersRepository(this.Entities);
            ClientRepo = new ClientsRepository(this.Entities);
        }
        public LogEntryManager(SemDataEntities entities)
            : base(entities)
        {
            ErrorLogRepo = new ErrorLogRepository(entities);
            Repo = new SEMLogRepository(entities);
            EntryPartRepo = new SEMLogEntryPartRepository(entities);
            EntryTypeRepo = new SEMLogEntryTypeRepository(entities);
            UserRepo = new UsersRepository(entities);
            ClientRepo = new ClientsRepository(entities);
        }

        /// <summary>
        /// Az összes log bejegyzés lekérdezése
        /// </summary>
        /// <returns></returns>
        public List<SEMLogEntryViewModel> GetAllLogEntries()
        {
            return Repo.GetAll().ToList().Select(logEntry => logEntry.GetViewModel()).ToList();
        }

        public SEMLogEntryViewModel GetById(int id)
        {
            SEMLogEntryViewModel result = null;
            LogEntry entryById = Repo.GetById(id);
            if (entryById != null)
            {
                result = entryById.GetViewModel();
            }
            return result;
        }

        /// <summary>
        /// Az elérhető bejegyzéstípusok listájának lekérése
        /// </summary>
        /// <returns></returns>
        public List<KeyValuePair<int, string>> GetAvailableLogentryTypes()
        {
            List<KeyValuePair<int, string>> result = new List<KeyValuePair<int, string>>();
            try
            {
                EntryTypeRepo.GetAll().ToList().ForEach(et =>
                    result.Add(new KeyValuePair<int, string>(et.Id, et.TypeDisplayName))
                    );
            }
            catch (Exception ex)
            {
                ErrorLogRepo.AddErrorLog(MethodInfo.GetCurrentMethod().DeclaringType.Name, MethodInfo.GetCurrentMethod().Name, ex.ToString(), String.Empty);
            }
            return result;
        }

        public List<string> GetAvailableLogentryClients()
        {
            List<string> result = new List<string>();
            try
            {
                result = ClientRepo.GetAll().Select(cl => cl.ClientName).ToList();
            }
            catch (Exception ex)
            {
                ErrorLogRepo.AddErrorLog(MethodInfo.GetCurrentMethod().DeclaringType.Name, MethodInfo.GetCurrentMethod().Name, ex.ToString(), String.Empty);
            }
            
            return result;
        }

        public List<string> GetAvailableSampleIdentifiers()
        {
            List<string> result = new List<string>();
            try
            {
                //result = Logentry.GetAll().Select(cl => cl.ClientName).ToList();
            }
            catch (Exception ex)
            {
                ErrorLogRepo.AddErrorLog(MethodInfo.GetCurrentMethod().DeclaringType.Name, MethodInfo.GetCurrentMethod().Name, ex.ToString(), String.Empty);
            }
            return result;
        }

        /// <summary>
        /// A legújabb bejegyzés lekérése
        /// </summary>
        /// <returns></returns>
        public SEMLogEntryViewModel GetNewest()
        {
            try
            {
                SEMLogEntryViewModel viewModel = Repo.GetAll().OrderByDescending(entry => entry.Created).First().GetViewModel();
                return viewModel;
            }
            catch (Exception ex)
            {
                ErrorLogRepo.AddErrorLog(MethodInfo.GetCurrentMethod().DeclaringType.Name, MethodInfo.GetCurrentMethod().Name, ex.ToString(), String.Empty);
                return null;
            }
        }

        /// <summary>
        /// Adding new log entry with an initial log entry part.
        /// </summary>
        /// <param name="model"></param>
        /// <param name="userName"></param>
        /// <returns></returns>
        public bool InsertNewLogEntry(SEMLogEntryViewModel model, string userName)
        {
            bool result = true;
            try
            {
                int userId = UserRepo.GetUserId(userName);
                if (userId > 0)
                {
                    LogEntry entry = new LogEntry
                    {
                        EntryBegin = model.EntryBegin,
                        CreatedByUserId = userId,
                        EntryEnd = model.EntryEnd,
                        Created = DateTime.Now
                    };
                    //ha van kezdeti bejegyzésrész, akkor azt is hozzáadjuk
                    if (!String.IsNullOrEmpty(model.InitialEntry))
                    {
                        var partType = EntryTypeRepo.GetAll().SingleOrDefault(t => t.Id == (int)model.InitialEntryType);
                        if (partType != null)
                        {
                            entry.LogEntryParts.Add(new LogEntryPart
                            {
                                EntryPartAddedByUserId = userId,
                                EntryPartBegin = DateTime.Now,
                                EntryPartDescription = model.InitialEntry,
                                EntryPartTypeId = partType.Id
                            });
                            try
                            {
                                Repo.Insert(entry);
                                Repo.Save();
                            }
                            catch (Exception ex)
                            {
                                result = false;
                                ErrorLogRepo.AddErrorLog(MethodInfo.GetCurrentMethod().DeclaringType.Name, MethodInfo.GetCurrentMethod().Name,
                                    ex.ToString(), String.Empty);
                            }

                        }
                        else
                        {
                            ErrorLogRepo.AddErrorLog(MethodInfo.GetCurrentMethod().DeclaringType.Name, MethodInfo.GetCurrentMethod().Name,
                                    "Part típus nem található", model.InitialEntryType.ToString());
                        }
                    }

                }
                else
                {
                    //TODO: log error
                }
            }
            catch (Exception ex)
            {
                ErrorLogRepo.AddErrorLog(MethodInfo.GetCurrentMethod().DeclaringType.Name, MethodInfo.GetCurrentMethod().Name, ex.ToString(), String.Empty);
                result = false;
            }
            return result;
        }

        public bool InsertNewEntryPart(SEMLogEntryPartViewModel model, int entryId, string userName)
        {
            bool result = true;
            try
            {
                //az egyed lekérése
                LogEntry entry = Repo.GetById(entryId);
                int userId = UserRepo.GetUserId(userName);

                LogEntryPart entryPart = new LogEntryPart
                {
                    EntryPartAddedByUserId = userId,
                    EntryPartBegin = DateTime.Now,
                    EntryPartTypeId = (int)model.EntryPartType,
                    LogEntryId = entryId,
                };
                if (model.EntryPartType == Common.Enums.SemLogEntryPartType.Error)
                {
                    entryPart.ErrorDescription = model.PartDescriptions;
                }
                else
                {
                    if (model.EntryPartType == Common.Enums.SemLogEntryPartType.DetectorRepair
                        || model.EntryPartType == Common.Enums.SemLogEntryPartType.GeneralRepair)
                    {
                        entryPart.RepairDescriptions = model.PartDescriptions;
                    }
                    else
                    {
                        entryPart.EntryPartDescription = model.PartDescriptions;
                    }
                }
                entry.LogEntryParts.Add(entryPart);
                Repo.Save();
            }
            catch (Exception ex)
            {
                ErrorLogRepo.AddErrorLog(MethodInfo.GetCurrentMethod().DeclaringType.Name, MethodInfo.GetCurrentMethod().Name, ex.ToString(), String.Empty);
            }
            return result;
        }

        public SEMLogEntryPartViewModel GetNewestPart(int entryId)
        {
            SEMLogEntryPartViewModel result = null;
            try
            {
                LogEntry entry = Repo.GetById(entryId);
                if (entry != null)
                {
                    result = entry.LogEntryParts.OrderByDescending(part => part.EntryPartBegin).First().GetViewModel();
                }
                else
                {
                    //TODO: log error
                }
            }
            catch (Exception ex)
            {
                ErrorLogRepo.AddErrorLog(MethodInfo.GetCurrentMethod().DeclaringType.Name, MethodInfo.GetCurrentMethod().Name, ex.ToString(), String.Empty);
            }
            return result;
        }

        public bool CloseEntry(int entryId, DateTime closeDate)
        {
            bool result = true;
            try
            {
                LogEntry entry = Repo.GetById(entryId);
                if (entry != null)
                {
                    entry.EntryEnd = closeDate;
                    Repo.Save();
                }
                else
                {
                    result = false;
                }
            }
            catch (Exception ex)
            {
                ErrorLogRepo.AddErrorLog(MethodInfo.GetCurrentMethod().DeclaringType.Name, MethodInfo.GetCurrentMethod().Name, ex.ToString(), String.Empty);
                result = false;
            }
            return result;
        }

        public bool EditEntryPart(SEMLogEntryPartViewModel model)
        {
            bool result = true;
            try
            {
                LogEntryPart entryPart = Repo.GetById(model.LogEntryId).LogEntryParts.SingleOrDefault(part => part.Id == model.Id);
                if (entryPart != null)
                {
                    LogEntryPartType partType = EntryTypeRepo.GetById((int)model.EntryPartType);
                    if (partType != null)
                    {
                        entryPart.EntryPartTypeId = partType.Id;
                        //csak a típus és a leírás szerkeszthető
                        if (model.EntryPartType == Common.Enums.SemLogEntryPartType.Error)
                        {
                            //a hiba leírása az átadott szöveg
                            //a másik két leírási mezőt ürítjük, hogy ne maradjon hibás szöveg bent.
                            entryPart.ErrorDescription = model.PartDescriptions;
                            entryPart.EntryPartDescription = String.Empty;
                            entryPart.RepairDescriptions = string.Empty;
                        }
                        else
                        {
                            if (model.EntryPartType == Common.Enums.SemLogEntryPartType.DetectorRepair
                                || model.EntryPartType == Common.Enums.SemLogEntryPartType.GeneralRepair)
                            {
                                entryPart.RepairDescriptions = model.PartDescriptions;
                                entryPart.ErrorDescription = String.Empty;
                                entryPart.EntryPartDescription = String.Empty;
                            }
                            else
                            {
                                entryPart.EntryPartDescription = model.PartDescriptions;
                                entryPart.ErrorDescription = String.Empty;
                                entryPart.RepairDescriptions = String.Empty;
                            }
                        }
                        Repo.Save();
                    }
                    else
                    {
                        ErrorLogRepo.AddErrorLog(
                           MethodInfo.GetCurrentMethod().DeclaringType.Name,
                           MethodInfo.GetCurrentMethod().Name,
                           "Nem található bejegyzésrész-típus",
                           String.Format("Bejegyzés-típus {0}", model.EntryPartType.ToString()));
                    }
                }
                else
                {
                    ErrorLogRepo.AddErrorLog(
                        MethodInfo.GetCurrentMethod().DeclaringType.Name,
                        MethodInfo.GetCurrentMethod().Name,
                        "Nem található bejegyzésrész",
                        String.Format("Bejegyzés id: {0}, Bejegyzésrész id: {1}", model.LogEntryId, model.Id));
                }
            }
            catch (Exception ex)
            {
                ErrorLogRepo.AddErrorLog(MethodInfo.GetCurrentMethod().DeclaringType.Name, MethodInfo.GetCurrentMethod().Name, ex.ToString(), String.Empty);
                result = false;
            }
            return result;
        }

        public bool DeleteEntryPart(SEMLogEntryPartViewModel model)
        {
            bool result = true;
            try
            {
                LogEntryPart entryPart = Repo.GetById(model.LogEntryId).LogEntryParts.SingleOrDefault(part => part.Id == model.Id);
                if (entryPart != null)
                {
                    EntryPartRepo.Delete(entryPart);
                    Repo.Save();
                }
                else
                {
                    ErrorLogRepo.AddErrorLog(
                        MethodInfo.GetCurrentMethod().DeclaringType.Name,
                        MethodInfo.GetCurrentMethod().Name,
                        "Nem található bejegyzésrész",
                        String.Format("Bejegyzés id: {0}, Bejegyzésrész id: {1}", model.LogEntryId, model.Id));
                }
            }
            catch (Exception ex)
            {
                ErrorLogRepo.AddErrorLog(MethodInfo.GetCurrentMethod().DeclaringType.Name, MethodInfo.GetCurrentMethod().Name, ex.ToString(), String.Empty);
                result = false;
            }
            return result;
        }

        public SEMLogEntryPartViewModel GetEntryPartViewModel(int entryId, int entryPartId)
        {
            try
            {
                LogEntry entry = Repo.GetById(entryId);
                if (entry != null)
                {
                    LogEntryPart entryPart = entry.LogEntryParts.SingleOrDefault(part => part.Id == entryPartId);
                    if (entryPartId != null)
                    {
                        return entryPart.GetViewModel();
                    }
                    else
                    {
                        ErrorLogRepo.AddErrorLog(
                            MethodInfo.GetCurrentMethod().DeclaringType.Name,
                            MethodInfo.GetCurrentMethod().Name,
                            "Nem található bejegyzésrész",
                            String.Format("Bejegyzés id: {0}, Bejegyzésrész id: {1}", entryId, entryPartId));
                    }
                }
                else
                {
                    ErrorLogRepo.AddErrorLog(
                        MethodInfo.GetCurrentMethod().DeclaringType.Name,
                        MethodInfo.GetCurrentMethod().Name,
                        "Nem található bejegyzés",
                        String.Format("Bejegyzés id: {0}", entryId));
                }
            }
            catch (Exception ex)
            {
                ErrorLogRepo.AddErrorLog(MethodInfo.GetCurrentMethod().DeclaringType.Name, MethodInfo.GetCurrentMethod().Name, ex.ToString(), String.Empty);
            }
            return null;
        }

    }
}
